package org.snackframework.util;

import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.commons.EmptyVisitor;

public class ParameterNameDiscoveringVisitor extends EmptyVisitor
{
	private String methodNameToMatch;

	private String descriptorToMatch;

	public int numParamsExpected;
	
	/*
	 * The nth entry contains the slot index of the LVT table entry holding the
	 * argument name for the nth parameter.
	 */
	public int[] lvtSlotIndex;

	public String[] parameterNames;
	
	public ParameterNameDiscoveringVisitor(String name, boolean isStatic, Class[] paramTypes) {
		this.methodNameToMatch = name;
		this.numParamsExpected = paramTypes.length;
		computeLvtSlotIndices(isStatic, paramTypes);
	}
	
	public void setDescriptorToMatch(String descriptor) {
		this.descriptorToMatch = descriptor;			
	}

	public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
		if (name.equals(this.methodNameToMatch) && desc.equals(this.descriptorToMatch)) {
			return new LocalVariableTableVisitor(this, isStatic(access));
		} 
		else {
			// Not interested in this method...
			return null;
		}
	}
	
	private boolean isStatic(int access) {
		return ((access & Opcodes.ACC_STATIC) > 0);
	}

	public String[] getParameterNames() {
		return this.parameterNames;
	}

	private void computeLvtSlotIndices(boolean isStatic, Class[] paramTypes) {
		this.lvtSlotIndex = new int[paramTypes.length];
		int nextIndex = (isStatic ? 0 : 1);
		for (int i = 0; i < paramTypes.length; i++) {
			this.lvtSlotIndex[i] = nextIndex;
			if (isWideType(paramTypes[i])) {
				nextIndex += 2;
			}
			else {
				nextIndex++;
			}
		}
	}
	
	private boolean isWideType(Class aType) {
		return (aType == Long.TYPE || aType == Double.TYPE);
	}

}
